﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using A14_Ex02_Adam_300604568_Chen_20131689.Properties;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;

public class FormGamePlay : Form
{
    private const char k_XChar = 'X';
    private const string k_XStr = "X";
    private const string k_OStr = "O";
    private const string k_CoinRed = "CoinRed";
    private const string k_CoinYellow = "CoinYellow";
    private const string k_AboutFilePath = @"C:\FourInARowHelp.txt";
    private List<ColumnNumberedButton> m_ColumnNumberedButtonsList = null;
    private BoardButton[,] m_BoardButtonsArray = null;
    private int m_BoardViewRowSize = 0;
    private int m_BoardViewColSize = 0;
    private GameEngine.eGameMoveStatus m_CurrentGameStatus = GameEngine.eGameMoveStatus.Continue;
    private GameEngine.ePlayerIndex m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
    private GameEngine m_GameEngine = null;
    private bool m_IsTwoUserPlayers = false;
    private StatusStrip statusStrip1;
    private ToolStripStatusLabel toolStripStatusLabelCurrentPlayerShow;
    private ToolStripStatusLabel toolStripStatusLabelCurrentPlayer;
    private ToolStripStatusLabel toolStripStatusLabelPlayerA;
    private ToolStripStatusLabel toolStripStatusLabelPlayerB;
    private ToolStripStatusLabel toolStripStatusLabel2; 
    private string m_FirstPlayerName = string.Empty;
    private string m_SecondPlayerName = string.Empty;
    private MenuStrip menuStrip1;
    private ToolStripMenuItem gameToolStripMenuItem;
    private ToolStripMenuItem startANewGameToolStripMenuItem;
    private ToolStripMenuItem startANewTournirToolStripMenuItem;
    private ToolStripMenuItem propertiesToolStripMenuItem;
    private ToolStripSeparator toolStripSeparator2;
    private ToolStripMenuItem exitToolStripMenuItem;
    private ToolStripMenuItem helpToolStripMenuItem;
    private ToolStripMenuItem howToPlayToolStripMenuItem;
    private ToolStripSeparator toolStripSeparator1;
    private ToolStripMenuItem aboutToolStripMenuItem;
    private Region m_DefaultBoardButtonRegion = null;
    private GraphicsPath m_NewGraphicPath = null;
    private bool v_IsUserChangedProperties = false;
    private FormGameSettings m_FormGameSettings = new FormGameSettings();
    private Timer m_TimerFall;
    private Timer m_TimerConnectedFour;
    private List<BoardButton> m_ConnectedFour = new List<BoardButton>();
    private Panel m_Panel;
    private PictureBox m_PictureBoxCursorDisc = new PictureBox();
    private int m_FallenDiscColumn = 0;
    private IContainer components;
    private BoardButton m_BoardButtonToFallTo = null;
    private bool v_IsDiscFinishedFalling = true;
    private PictureBox m_PictureBoxFallenDisc;
    private int m_PcChosenCol = 0;
    private bool v_IsWinner = false;
    private GameEngine.ePlayerIndex? m_PlayerWinnerIndex = null;

    public FormGamePlay(int i_RowSize, int i_ColSize, bool i_IsTwoPlayers, string i_FirstPlayerName, string i_SecondPlayerName)
    {
        this.m_BoardViewColSize = i_ColSize;
        this.m_BoardViewRowSize = i_RowSize;
        this.m_IsTwoUserPlayers = i_IsTwoPlayers;
        this.m_FirstPlayerName = i_FirstPlayerName;
        this.m_SecondPlayerName = i_SecondPlayerName;

        this.m_GameEngine = new GameEngine(this.m_BoardViewRowSize, this.m_BoardViewColSize, this.m_IsTwoUserPlayers);
        this.m_ColumnNumberedButtonsList = new List<ColumnNumberedButton>(i_ColSize);
        this.m_BoardButtonsArray = new BoardButton[i_RowSize, i_ColSize];

        this.initializeBoardButtonsEventHandlers();
        this.initializePlayersEventHandlers();

        this.InitializeComponent();

        this.loadColsButtons(this.m_BoardViewColSize);
        this.loadBoardButtons(this.m_BoardViewRowSize, this.m_BoardViewColSize);
        this.setPanelSize();
        this.initializeMouseCursorDisc();

        this.toolStripStatusLabelPlayerA.Text = string.Format(@"{0}: {1},", m_FirstPlayerName, 0);
        this.toolStripStatusLabelPlayerB.Text = string.Format(@"{0}: {1},", m_SecondPlayerName, 0);
        this.toolStripStatusLabelCurrentPlayer.Text = m_FirstPlayerName;
    }

    private void initializeMouseCursorDisc()
    {
        bool IsFirstPixelIsTransparent = true;
        m_PictureBoxCursorDisc.Region = new Region(quickCalculateGraphicsPath(Resources.FullCellYellow, IsFirstPixelIsTransparent));
        m_PictureBoxCursorDisc.Image = Resources.CoinRed;
        m_PictureBoxCursorDisc.Size = Resources.CoinRed.Size;
        m_PictureBoxCursorDisc.Enabled = true;
        m_PictureBoxCursorDisc.Visible = true;

        Point Location = System.Windows.Forms.Cursor.Position;
        m_PictureBoxCursorDisc.Location = new Point(Location.X + Resources.CoinRed.Width, Location.Y + Resources.CoinRed.Height);
        this.m_Panel.Controls.Add(m_PictureBoxCursorDisc);
    }

    private void setPanelSize()
    {
        int width = m_ColumnNumberedButtonsList[0].Width * m_BoardViewColSize;
        int height = m_ColumnNumberedButtonsList[0].Height * (m_BoardViewRowSize + 1);
        this.m_Panel.Size = new Size(width, height);
    }

    private void initializeBoardButtonsEventHandlers()
    {
        Cell[,] arr = this.m_GameEngine.BoardMatrix;

        foreach (Cell item in arr)
        {
            item.CellChange += new CellChangeDelegate(this.On_CellChange);
        }
    }

    private void initializePlayersEventHandlers()
    {
        this.m_GameEngine.GetPlayerByIndex(0).ScoreChange += new ScoreChangeDelegate(this.On_ScoreChange);
        this.m_GameEngine.GetPlayerByIndex(1).ScoreChange += new ScoreChangeDelegate(this.On_ScoreChange);
    }

    public void On_ScoreChange(object i_Obj)
    {
        Player CurrentPlayer = i_Obj as Player;
        
        if (CurrentPlayer.PlayerSymbol.Equals(k_XChar))
        {
            this.toolStripStatusLabelPlayerA.Text = string.Format(@"{0}: {1},", this.m_FirstPlayerName, CurrentPlayer.Score); 
        }

        else
        {
            this.toolStripStatusLabelPlayerB.Text = string.Format(@"{0}: {1}", this.m_SecondPlayerName, CurrentPlayer.Score); 
        }
    }

    private void flashConnectedFour()
    {
        m_ConnectedFour.Clear();

        foreach (Cell cell in m_GameEngine.ListOfWinningCells)
        {
            BoardButton Button = m_BoardButtonsArray[cell.R_RowIndex, cell.R_ColIndex];
            m_ConnectedFour.Add(Button);
        }

        m_TimerConnectedFour.Enabled = true;
        m_TimerConnectedFour.Start();
    }

    public void On_CellChange(object i_Obj)
    {
        Cell CurrentCell = i_Obj as Cell;

        m_BoardButtonToFallTo = m_BoardButtonsArray[CurrentCell.R_RowIndex, CurrentCell.R_ColIndex];

        string CurrentCellSymbol = CurrentCell.ToString();

        if (CurrentCellSymbol.Equals(string.Empty))
        {
            m_PictureBoxFallenDisc.Image = null;
            m_PictureBoxFallenDisc.Name = string.Empty;
            m_PictureBoxFallenDisc.Enabled = false;
            m_PictureBoxFallenDisc.Visible = false;
        }
        else
        {
            ColumnNumberedButton ChosenColumnButton = m_ColumnNumberedButtonsList[m_FallenDiscColumn - 1];
            m_PictureBoxFallenDisc.Location = ChosenColumnButton.Location;

            if (CurrentCellSymbol.Equals(k_XStr))
            {
                m_PictureBoxFallenDisc.Image = Resources.CoinRed;
                m_PictureBoxFallenDisc.Name = k_CoinRed;
            }
            else if (CurrentCellSymbol.Equals(k_OStr))
            {
                m_PictureBoxFallenDisc.Image = Resources.CoinYellow;
                m_PictureBoxFallenDisc.Name = k_CoinYellow;
                m_PcChosenCol = 0;
            }

            enableFallenDisc();
        }
    }

    private void enableFallenDisc()
    {
        m_PictureBoxFallenDisc.Enabled = true;
        m_PictureBoxFallenDisc.Visible = true;
        m_PictureBoxFallenDisc.Region = m_DefaultBoardButtonRegion;

        this.m_Panel.Controls.Add(m_PictureBoxFallenDisc);
        v_IsDiscFinishedFalling = false;
        m_TimerFall.Enabled = true;
        m_TimerFall.Start();
    }

    public enum eErrorMessage
    {
        ColumnIsFull = 0,
        InvalidBoardSize,
        InvalidGameMode,
        InvalidKeyPressed,
        BoardIsFull
    }

    private void InitializeComponent()
    {
        this.components = new System.ComponentModel.Container();
        this.statusStrip1 = new System.Windows.Forms.StatusStrip();
        this.toolStripStatusLabelCurrentPlayerShow = new System.Windows.Forms.ToolStripStatusLabel();
        this.toolStripStatusLabelCurrentPlayer = new System.Windows.Forms.ToolStripStatusLabel();
        this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
        this.toolStripStatusLabelPlayerA = new System.Windows.Forms.ToolStripStatusLabel();
        this.toolStripStatusLabelPlayerB = new System.Windows.Forms.ToolStripStatusLabel();
        this.menuStrip1 = new System.Windows.Forms.MenuStrip();
        this.gameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.startANewGameToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.startANewTournirToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.propertiesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
        this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.howToPlayToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
        this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
        this.m_TimerFall = new System.Windows.Forms.Timer(this.components);
        this.m_TimerConnectedFour = new System.Windows.Forms.Timer(this.components);
        this.m_Panel = new System.Windows.Forms.Panel();
        this.m_PictureBoxFallenDisc = new System.Windows.Forms.PictureBox();
        this.statusStrip1.SuspendLayout();
        this.menuStrip1.SuspendLayout();
        this.m_Panel.SuspendLayout();
        ((System.ComponentModel.ISupportInitialize)(this.m_PictureBoxFallenDisc)).BeginInit();
        this.SuspendLayout();
        // 
        // statusStrip1
        // 
        this.statusStrip1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
        this.statusStrip1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
        this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.toolStripStatusLabelCurrentPlayerShow,
            this.toolStripStatusLabelCurrentPlayer,
            this.toolStripStatusLabel2,
            this.toolStripStatusLabelPlayerA,
            this.toolStripStatusLabelPlayerB});
        this.statusStrip1.Location = new System.Drawing.Point(0, 253);
        this.statusStrip1.Name = "statusStrip1";
        this.statusStrip1.Size = new System.Drawing.Size(374, 22);
        this.statusStrip1.TabIndex = 0;
        this.statusStrip1.Text = "statusStrip1";
        // 
        // toolStripStatusLabelCurrentPlayerShow
        // 
        this.toolStripStatusLabelCurrentPlayerShow.Name = "toolStripStatusLabelCurrentPlayerShow";
        this.toolStripStatusLabelCurrentPlayerShow.Size = new System.Drawing.Size(85, 17);
        this.toolStripStatusLabelCurrentPlayerShow.Text = "Current Player:";
        // 
        // toolStripStatusLabelCurrentPlayer
        // 
        this.toolStripStatusLabelCurrentPlayer.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
        this.toolStripStatusLabelCurrentPlayer.Name = "toolStripStatusLabelCurrentPlayer";
        this.toolStripStatusLabelCurrentPlayer.Size = new System.Drawing.Size(50, 17);
        this.toolStripStatusLabelCurrentPlayer.Text = "Player A";
        // 
        // toolStripStatusLabel2
        // 
        this.toolStripStatusLabel2.Name = "toolStripStatusLabel2";
        this.toolStripStatusLabel2.Padding = new System.Windows.Forms.Padding(0, 0, 60, 0);
        this.toolStripStatusLabel2.Size = new System.Drawing.Size(60, 17);
        // 
        // toolStripStatusLabelPlayerA
        // 
        this.toolStripStatusLabelPlayerA.Name = "toolStripStatusLabelPlayerA";
        this.toolStripStatusLabelPlayerA.Size = new System.Drawing.Size(62, 17);
        this.toolStripStatusLabelPlayerA.Text = "PlayerA: 0,";
        // 
        // toolStripStatusLabelPlayerB
        // 
        this.toolStripStatusLabelPlayerB.Name = "toolStripStatusLabelPlayerB";
        this.toolStripStatusLabelPlayerB.Size = new System.Drawing.Size(58, 17);
        this.toolStripStatusLabelPlayerB.Text = "PlayerB: 0";
        // 
        // menuStrip1
        // 
        this.menuStrip1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
        this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.gameToolStripMenuItem,
            this.helpToolStripMenuItem});
        this.menuStrip1.Location = new System.Drawing.Point(0, 0);
        this.menuStrip1.Name = "menuStrip1";
        this.menuStrip1.Size = new System.Drawing.Size(374, 24);
        this.menuStrip1.TabIndex = 1;
        this.menuStrip1.Text = "menuStrip1";
        // 
        // gameToolStripMenuItem
        // 
        this.gameToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.startANewGameToolStripMenuItem,
            this.startANewTournirToolStripMenuItem,
            this.propertiesToolStripMenuItem,
            this.toolStripSeparator2,
            this.exitToolStripMenuItem});
        this.gameToolStripMenuItem.Name = "gameToolStripMenuItem";
        this.gameToolStripMenuItem.Size = new System.Drawing.Size(50, 20);
        this.gameToolStripMenuItem.Text = "Game";
        // 
        // startANewGameToolStripMenuItem
        // 
        this.startANewGameToolStripMenuItem.Name = "startANewGameToolStripMenuItem";
        this.startANewGameToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
        this.startANewGameToolStripMenuItem.Text = "Start a New Game";
        this.startANewGameToolStripMenuItem.Click += new System.EventHandler(this.startANewGameToolStripMenuItem_Click);
        // 
        // startANewTournirToolStripMenuItem
        // 
        this.startANewTournirToolStripMenuItem.Name = "startANewTournirToolStripMenuItem";
        this.startANewTournirToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
        this.startANewTournirToolStripMenuItem.Text = "Start a New Tournir";
        this.startANewTournirToolStripMenuItem.Click += new System.EventHandler(this.startANewTournirToolStripMenuItem_Click);
        // 
        // propertiesToolStripMenuItem
        // 
        this.propertiesToolStripMenuItem.Name = "propertiesToolStripMenuItem";
        this.propertiesToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
        this.propertiesToolStripMenuItem.Text = "Properties";
        this.propertiesToolStripMenuItem.Click += new System.EventHandler(this.propertiesToolStripMenuItem_Click);
        // 
        // toolStripSeparator2
        // 
        this.toolStripSeparator2.Name = "toolStripSeparator2";
        this.toolStripSeparator2.Size = new System.Drawing.Size(173, 6);
        // 
        // exitToolStripMenuItem
        // 
        this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
        this.exitToolStripMenuItem.Size = new System.Drawing.Size(176, 22);
        this.exitToolStripMenuItem.Text = "Exit";
        this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click);
        // 
        // helpToolStripMenuItem
        // 
        this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.howToPlayToolStripMenuItem,
            this.toolStripSeparator1,
            this.aboutToolStripMenuItem});
        this.helpToolStripMenuItem.Name = "helpToolStripMenuItem";
        this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
        this.helpToolStripMenuItem.Text = "Help";
        // 
        // howToPlayToolStripMenuItem
        // 
        this.howToPlayToolStripMenuItem.Name = "howToPlayToolStripMenuItem";
        this.howToPlayToolStripMenuItem.Size = new System.Drawing.Size(143, 22);
        this.howToPlayToolStripMenuItem.Text = "How to play?";
        this.howToPlayToolStripMenuItem.Click += new System.EventHandler(this.howToPlayToolStripMenuItem_Click);
        // 
        // toolStripSeparator1
        // 
        this.toolStripSeparator1.Name = "toolStripSeparator1";
        this.toolStripSeparator1.Size = new System.Drawing.Size(140, 6);
        // 
        // aboutToolStripMenuItem
        // 
        this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
        this.aboutToolStripMenuItem.Size = new System.Drawing.Size(143, 22);
        this.aboutToolStripMenuItem.Text = "About";
        this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
        // 
        // m_TimerFall
        // 
        this.m_TimerFall.Interval = 1;
        this.m_TimerFall.Tick += new System.EventHandler(this.m_TimerFall_Tick);
        // 
        // m_TimerConnectedFour
        // 
        this.m_TimerConnectedFour.Interval = 50;
        this.m_TimerConnectedFour.Tick += new System.EventHandler(this.m_TimerConnectedFour_Tick);
        // 
        // panel1
        // 
        this.m_Panel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(255)))));
        this.m_Panel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
        this.m_Panel.Controls.Add(this.m_PictureBoxFallenDisc);
        this.m_Panel.Location = new System.Drawing.Point(13, 40);
        this.m_Panel.Name = "panel1";
        this.m_Panel.Size = new System.Drawing.Size(349, 201);
        this.m_Panel.TabIndex = 2;
        this.m_Panel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.On_MouseMove);
        this.m_Panel.Resize += new System.EventHandler(this.m_Panel_Resize);
        // 
        // m_PictureBoxFallenDisc
        // 
        this.m_PictureBoxFallenDisc.BackColor = System.Drawing.Color.Transparent;
        this.m_PictureBoxFallenDisc.Enabled = false;
        this.m_PictureBoxFallenDisc.Location = new System.Drawing.Point(127, 62);
        this.m_PictureBoxFallenDisc.Name = "m_PictureBoxFallenDisc";
        this.m_PictureBoxFallenDisc.Size = new System.Drawing.Size(60, 60);
        this.m_PictureBoxFallenDisc.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
        this.m_PictureBoxFallenDisc.TabIndex = 0;
        this.m_PictureBoxFallenDisc.TabStop = false;
        this.m_PictureBoxFallenDisc.Visible = false;
        // 
        // FormGamePlay
        // 
        this.AutoSize = true;
        this.BackColor = System.Drawing.Color.AliceBlue;
        this.ClientSize = new System.Drawing.Size(374, 275);
        this.Controls.Add(this.m_Panel);
        this.Controls.Add(this.statusStrip1);
        this.Controls.Add(this.menuStrip1);
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
        this.MainMenuStrip = this.menuStrip1;
        this.Name = "FormGamePlay";
        this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
        this.Text = "4 In A Row";
        this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.On_MouseMove);
        this.statusStrip1.ResumeLayout(false);
        this.statusStrip1.PerformLayout();
        this.menuStrip1.ResumeLayout(false);
        this.menuStrip1.PerformLayout();
        this.m_Panel.ResumeLayout(false);
        this.m_Panel.PerformLayout();
        ((System.ComponentModel.ISupportInitialize)(this.m_PictureBoxFallenDisc)).EndInit();
        this.ResumeLayout(false);
        this.PerformLayout();
    }

    private void loadBoardButtons(int i_RowSize, int i_ColSize)
    {
        Cell[,] BoardCellsMatrix = this.m_GameEngine.BoardMatrix;

        Bitmap BoardButtonBitmap = Resources.EmptyCell;

        bool IsFirstPixelIsTransparent = false;
        m_NewGraphicPath = quickCalculateGraphicsPath(BoardButtonBitmap, IsFirstPixelIsTransparent);

        for (int CurrentRow = 0; CurrentRow < i_RowSize; CurrentRow++)
        {
            for (int CurrentCol = 0; CurrentCol < i_ColSize; CurrentCol++)
            {
                BoardButton CurrentBoardButton = new BoardButton();
                this.m_BoardButtonsArray[CurrentRow, CurrentCol] = CurrentBoardButton;
            
                if (CurrentRow == 0 && CurrentCol == 0)
                {
                    m_DefaultBoardButtonRegion = m_BoardButtonsArray[0, 0].Region;
                }

                CurrentBoardButton.BackgroundImage = BoardButtonBitmap;
                CurrentBoardButton.Region = new Region(m_NewGraphicPath);
                CurrentBoardButton.Top = this.m_ColumnNumberedButtonsList[CurrentCol].Height * (CurrentRow + 1);
                CurrentBoardButton.Left = this.m_ColumnNumberedButtonsList[CurrentCol].Left;
                CurrentBoardButton.MouseMove += new MouseEventHandler(this.On_MouseMove);
                this.m_Panel.Controls.Add(CurrentBoardButton);
            }
        }
    }

    private Bitmap initializeBoardButtonImage(Bitmap i_Bitmap)
    {
        Bitmap BoardButtonBitmap = i_Bitmap;
        Color FirstPixelColor = BoardButtonBitmap.GetPixel(0, 0);
        BoardButtonBitmap.SetPixel(BoardButtonBitmap.Width - 1, BoardButtonBitmap.Height - 1, FirstPixelColor);
        return BoardButtonBitmap;
    }

    private GraphicsPath quickCalculateGraphicsPath(Bitmap i_bitmap, bool i_IsFirstPixelTransparent)
    {
        GraphicsPath graphicsPath = new GraphicsPath();
        Color transparentColor = i_bitmap.GetPixel(0, 0);
        int startRegionArea = -1;
        Color pixelColor = Color.Empty;
        BitmapData bitmapdata = i_bitmap.LockBits(new Rectangle(0, 0, i_bitmap.Width, i_bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        IntPtr scanl = bitmapdata.Scan0;
        int yoffset = bitmapdata.Stride - (i_bitmap.Width * 3);

        unsafe
        {
            int bitmapheight = i_bitmap.Height;
            int bitmapwidth = i_bitmap.Width;

            byte* p = (byte*)(void*)scanl;
            for (int y = 0; y <= bitmapheight - 1; y++)
            {
                for (int x = 0; x <= bitmapwidth - 1; x++)
                {
                    int b = (int)p[0];
                    int g = (int)p[1];
                    int r = (int)p[2];
                    pixelColor = Color.FromArgb(r, g, b);

                    if (i_IsFirstPixelTransparent)
                    {
                        if (pixelColor == transparentColor && startRegionArea != -1)
                        {
                            graphicsPath.AddRectangle(new Rectangle(startRegionArea, y, (x - 1) - startRegionArea, 1));
                            startRegionArea = -1;
                        }

                        if (pixelColor != transparentColor && startRegionArea == -1)
                        {
                            startRegionArea = x;
                        }
                    }

                    else
                    {
                        if (pixelColor != transparentColor && startRegionArea != -1)
                        {
                            graphicsPath.AddRectangle(new Rectangle(startRegionArea, y, (x - 1) - startRegionArea, 1));
                            startRegionArea = -1;
                        }

                        if (pixelColor == transparentColor && startRegionArea == -1)
                        {
                            startRegionArea = x;
                        }
                    }
                    p += 3;
                }

                if (startRegionArea != -1)
                {
                    graphicsPath.AddRectangle(new Rectangle(startRegionArea, y, i_bitmap.Width - startRegionArea, 1));
                    startRegionArea = -1;
                }

                p += yoffset;
            }
        }

        i_bitmap.UnlockBits(bitmapdata);
        return graphicsPath;
    }

    private void loadColsButtons(int i_ColSize)
    {
        int left = 0;

        for (int CurrentColIndex = 1; CurrentColIndex <= i_ColSize; CurrentColIndex++)
        {
            ColumnNumberedButton CurrentColButton = new ColumnNumberedButton(CurrentColIndex);
            CurrentColButton.Left = left;
            CurrentColButton.TabIndex = CurrentColIndex;
            CurrentColButton.Click += new EventHandler(this.On_ButtonClick);
            CurrentColButton.MouseMove += new MouseEventHandler(this.On_MouseMove);
            CurrentColButton.Enabled = true;
            left += CurrentColButton.Width;

            this.m_Panel.Controls.Add(CurrentColButton);
            this.m_ColumnNumberedButtonsList.Add(CurrentColButton);
        }
    }

    private void On_ButtonClick(object i_Object, EventArgs i_EventArgs)
    {
        if (v_IsDiscFinishedFalling && !v_IsWinner)
        {
            ColumnNumberedButton ClickedButton = i_Object as ColumnNumberedButton;
            m_FallenDiscColumn = ClickedButton.TabIndex;
            m_PictureBoxCursorDisc.Visible = false;
            m_PictureBoxCursorDisc.Enabled = false;

            this.m_CurrentGameStatus = this.m_GameEngine.AddDisc(m_FallenDiscColumn, (int)this.m_CurrentPlayerIndex);
            this.handleGameStatus(ClickedButton);
        }
    }

    private Image getCurrentDiscImage()
    {
        Image CurrentImage = null;

        if (m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.FirstPlayer))
        {
            CurrentImage = Resources.CoinRed;
        }
        else
        {
            CurrentImage = Resources.CoinYellow;
        }

        return CurrentImage;
    }

    private void handleGameStatus(ColumnNumberedButton i_ClickedButton)
    {
        switch (this.m_CurrentGameStatus)
        {
            case GameEngine.eGameMoveStatus.PlayerWin:
                {
                    this.v_IsWinner = true;
                    this.m_PlayerWinnerIndex = m_CurrentPlayerIndex;
                    this.m_GameEngine.UpdateWinnerScore((int)this.m_CurrentPlayerIndex);
                    this.flashConnectedFour();
                    this.showPopup();
                    break;
                }

            case GameEngine.eGameMoveStatus.BoardIsFull:
                {
                    this.showPopup();
                    break;
                }

            case GameEngine.eGameMoveStatus.ColumnIsFull:
                {
                    this.handleCurrentPlayerIndex();
                    this.handlePcPlayerMove();
                    break;
                }

            case GameEngine.eGameMoveStatus.Continue:
                {
                    this.handleCurrentPlayerIndex();
                    this.handlePcPlayerMove();
                    break;
                }
        }
    }

    private void handlePcPlayerMove()
    {
        if (!this.m_IsTwoUserPlayers && this.m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.SecondPlayer) && !v_IsWinner)
        {
            Random r = new Random();

            m_PcChosenCol = r.Next(1, this.m_ColumnNumberedButtonsList.Count);
            ColumnNumberedButton ChosenColumnNumberedButton = this.m_ColumnNumberedButtonsList[m_PcChosenCol];

            this.On_ButtonClick(ChosenColumnNumberedButton, EventArgs.Empty);
        }
    }

    private void showPopup()
    {
        string PopupQuestion = string.Empty;
        string PopupTitle = string.Empty;

        this.getPopupDetails(ref PopupQuestion, ref PopupTitle);

        if (MessageBox.Show(PopupQuestion, PopupTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
        {
            this.initializeNewGame();
        }
        else
        {
            this.finishGame();
        }
    }

    private void initializeNewGame()
    {
        if (v_IsUserChangedProperties)
        {
            initializeNewProperties();
        }

        else
        {
            initializeSameProperties();
        }

        this.v_IsWinner = false;
        this.initializeMouseCursorDisc();
        this.m_TimerConnectedFour.Enabled = false;
        this.m_TimerConnectedFour.Stop();
        this.m_TimerFall.Enabled = false;
        this.m_TimerFall.Stop();
        this.m_PcChosenCol = 0;
        this.m_FallenDiscColumn = 0;
        this.m_BoardButtonToFallTo = null;
        this.m_ConnectedFour.Clear();
        this.v_IsDiscFinishedFalling = true;
    }

    private void initializeSameProperties()
    {
        this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
        this.toolStripStatusLabelCurrentPlayer.Text = getPlayerNameByIndex(m_CurrentPlayerIndex);
        this.m_CurrentGameStatus = GameEngine.eGameMoveStatus.Continue;
        this.m_GameEngine.MakeEmptyBoard();
        this.m_GameEngine.DiscsCounter = 0;
        this.makeBoardButtonsEmpty();
    }

    private void initializeNewProperties()
    {
        this.clearBoardButtonsEventHandlers();
        this.m_Panel.Controls.Clear();

        this.initializeGameEngine();

        this.m_ColumnNumberedButtonsList = new List<ColumnNumberedButton>(m_BoardViewColSize);
        this.m_BoardButtonsArray = new BoardButton[m_BoardViewRowSize, m_BoardViewColSize];

        this.initializeBoardButtonsEventHandlers();

        this.loadColsButtons(this.m_BoardViewColSize);
        this.loadBoardButtons(this.m_BoardViewRowSize, this.m_BoardViewColSize);
        this.setPanelSize();
        this.toolStripStatusLabelPlayerA.Text = string.Format(@"{0}: {1},", m_FirstPlayerName, this.m_GameEngine.GetPlayerScore(GameEngine.ePlayerIndex.FirstPlayer));
        this.toolStripStatusLabelPlayerB.Text = string.Format(@"{0}: {1}", m_SecondPlayerName, this.m_GameEngine.GetPlayerScore(GameEngine.ePlayerIndex.SecondPlayer));
        this.toolStripStatusLabelCurrentPlayer.Text = m_FirstPlayerName;
        this.v_IsUserChangedProperties = false;
    }

    private void initializeGameEngine()
    {
        int PlayerAScore = m_GameEngine.GetPlayerScore(GameEngine.ePlayerIndex.FirstPlayer);
        int PlayerBScore = m_GameEngine.GetPlayerScore(GameEngine.ePlayerIndex.SecondPlayer);

        this.m_GameEngine = new GameEngine(this.m_BoardViewRowSize, this.m_BoardViewColSize, this.m_IsTwoUserPlayers);

        this.m_GameEngine.SetPlayerScore(GameEngine.ePlayerIndex.FirstPlayer, PlayerAScore);
        this.m_GameEngine.SetPlayerScore(GameEngine.ePlayerIndex.SecondPlayer, PlayerBScore);
        initializePlayersEventHandlers();
    }

    private void clearBoardButtonsEventHandlers()
    {
        Cell[,] arr = this.m_GameEngine.BoardMatrix;

        foreach (Cell item in arr)
        {
            item.CellChange -= new CellChangeDelegate(this.On_CellChange);
        }
    }

    private void makeBoardButtonsEmpty()
    {
        foreach (ColumnNumberedButton CurrentColumnNumberedNumber in this.m_ColumnNumberedButtonsList)
        {
            CurrentColumnNumberedNumber.Enabled = true;
        }

        foreach (BoardButton CurrentBoardButton in this.m_BoardButtonsArray)
        {
            CurrentBoardButton.Region = new Region(m_NewGraphicPath);
            CurrentBoardButton.BackgroundImage = Resources.EmptyCell;
        }
    }

    private void getPopupDetails(ref string io_PopupQuestion, ref string io_PopupTitle)
    {
        switch (this.m_CurrentGameStatus)
        {
            case GameEngine.eGameMoveStatus.PlayerWin:
                {
                    io_PopupQuestion = this.getWinnerAnnounce();
                    io_PopupTitle = "A Win!!";
                    break;
                }

            case GameEngine.eGameMoveStatus.BoardIsFull:
                {
                    io_PopupQuestion = string.Format(
@"Tie!!
Another Round?");
                    io_PopupTitle = "A Tie!!";
                    break;
                }
        }
    }

    private void finishGame()
    {
        this.DialogResult = DialogResult.OK;
        this.Close();
    }

    private string getWinnerAnnounce()
    {
        string result = string.Empty;

        string PlayerName = this.getPlayerNameByIndex(this.m_CurrentPlayerIndex);
        result = string.Format(
@"{0} Won!!
Another Round?",
               PlayerName);

        return result;
    }

    private string getPlayerNameByIndex(GameEngine.ePlayerIndex currentPlayer)
    {
        string result = string.Empty;

        switch (currentPlayer)
        {
            case GameEngine.ePlayerIndex.FirstPlayer:
                {
                    result = m_FirstPlayerName;
                    break;
                }
            case GameEngine.ePlayerIndex.SecondPlayer:
                {
                    result = m_SecondPlayerName;
                    break;
                }
        }

        return result;
    }

    private void handleCurrentPlayerIndex()
    {
        if (this.m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.FirstPlayer))
        {
            this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.SecondPlayer;
            this.m_PictureBoxCursorDisc.Image = Resources.CoinYellow;
        }
        else
        {
            this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
            this.m_PictureBoxCursorDisc.Image = Resources.CoinRed;
        }
    }

    private void startANewGameToolStripMenuItem_Click(object sender, EventArgs e)
    {
        initializeNewGame();
    }

    private void exitToolStripMenuItem_Click(object sender, EventArgs e)
    {
        finishGame();
    }

    private void startANewTournirToolStripMenuItem_Click(object sender, EventArgs e)
    {
        m_GameEngine.ResetPlayersScore();
        initializeNewGame();
    }

    private void propertiesToolStripMenuItem_Click(object sender, EventArgs e)
    {
        initializeFormGameSettingsData();

        if (m_FormGameSettings.ShowDialog() == DialogResult.OK)
        {
            v_IsUserChangedProperties = true;

            saveFormGameSettingsData();

            if (MessageBox.Show("Start a new game?", "4 In A Row", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                initializeNewGame();
            }
            else
            {
                MessageBox.Show(
@"New board size will take effect
on the next game.", "4 In A Row", MessageBoxButtons.OK);
            }
        }
    }

    private void saveFormGameSettingsData()
    {
        m_FirstPlayerName = m_FormGameSettings.FirstPlayerName;
        m_SecondPlayerName = m_FormGameSettings.SecondPlayerName;
        m_IsTwoUserPlayers = m_FormGameSettings.IsTwoUserPlayers;
        m_BoardViewRowSize = m_FormGameSettings.RowSize;
        m_BoardViewColSize = m_FormGameSettings.ColSize;
    }

    private void initializeFormGameSettingsData()
    {
        m_FormGameSettings.FirstPlayerName = m_FirstPlayerName;
        m_FormGameSettings.SecondPlayerName = m_SecondPlayerName;
        m_FormGameSettings.IsTwoUserPlayers = m_IsTwoUserPlayers;
        m_FormGameSettings.RowSize = m_BoardViewRowSize;
        m_FormGameSettings.ColSize = m_BoardViewColSize;
    }

    private bool userChangedBoardSize()
    {
        bool result = false;

        if (!m_BoardViewColSize.Equals(m_FormGameSettings.ColSize))
        {
            result = true;
        }
        else if (!m_BoardViewRowSize.Equals(m_FormGameSettings.RowSize))
        {
            result = true;
        }

        return result;
    }

    private void m_Panel_Resize(object sender, EventArgs e)
    {
        int height = this.menuStrip1.Height + this.m_Panel.Height + this.statusStrip1.Height + (Resources.EmptyCell.Height / 2);
        int width = (this.m_Panel.Left * 2) + this.m_Panel.Width;
        this.ClientSize = new Size(width, height);
    }

    private void m_TimerConnectedFour_Tick(object sender, EventArgs e)
    {
        Random r = new Random();
        int next = r.Next(10);

        Bitmap ConnectedFourFlashBitmap = getCurrentConnectedFourFlashBitmap(next);

        foreach (BoardButton ConnectedFourBoardButton in m_ConnectedFour)
        {
            ConnectedFourBoardButton.BackgroundImage = ConnectedFourFlashBitmap;
        }
    }

    private Bitmap getCurrentConnectedFourFlashBitmap(int next)
    {
        Bitmap ConnectedFourFlashBitmap = null;

        if (next % 2 == 0 && m_PlayerWinnerIndex.Equals(GameEngine.ePlayerIndex.FirstPlayer))
        {
            ConnectedFourFlashBitmap = Resources.FullCellRedWin;
        }

        else if (m_PlayerWinnerIndex.Equals(GameEngine.ePlayerIndex.FirstPlayer))
        {
            ConnectedFourFlashBitmap = Resources.FullCellRed;
        }

        else if (next % 2 == 0 && m_PlayerWinnerIndex.Equals(GameEngine.ePlayerIndex.SecondPlayer))
        {
            ConnectedFourFlashBitmap = Resources.FullCellYellow;
        }

        else if (m_PlayerWinnerIndex.Equals(GameEngine.ePlayerIndex.SecondPlayer))
        {
            ConnectedFourFlashBitmap = Resources.FullCellYellowWin;
        }

        return ConnectedFourFlashBitmap;
    }

    private void howToPlayToolStripMenuItem_Click(object sender, EventArgs e)
    {
        MessageBox.Show(File.ReadAllText((k_AboutFilePath)), "How to play?");
    }

    private void m_TimerFall_Tick(object sender, EventArgs e)
    {
        if (m_PictureBoxFallenDisc.Bottom <= m_BoardButtonToFallTo.Bottom)
        {
            m_PictureBoxFallenDisc.Top += 4;
        }
        else
        {
            doWhenReachDown();
        }
    }

    private void doWhenReachDown()
    {
        disableFallenDisc();

        m_BoardButtonToFallTo.Region = m_DefaultBoardButtonRegion;

        if (m_PictureBoxFallenDisc.Name.Equals(k_CoinRed))
        {
            m_BoardButtonToFallTo.BackgroundImage = Resources.FullCellRed;
        }
        else if (m_PictureBoxFallenDisc.Name.Equals(k_CoinYellow))
        {
            m_BoardButtonToFallTo.BackgroundImage = Resources.FullCellYellow;
        }

        this.toolStripStatusLabelCurrentPlayer.Text = getPlayerNameByIndex(m_CurrentPlayerIndex);
        handlePcWaitingMove();

        m_PictureBoxCursorDisc.Visible = true;
        m_PictureBoxCursorDisc.Enabled = true;
    }

    private void handlePcWaitingMove()
    {
        Player NextPlayer = m_GameEngine.GetPlayerByIndex((int)m_CurrentPlayerIndex);

        if (m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.SecondPlayer) && NextPlayer.GetPlayerType.Equals(Player.ePlayerType.Pc))
        {
            ColumnNumberedButton ClickedButton = m_ColumnNumberedButtonsList[m_PcChosenCol];
            this.On_ButtonClick(ClickedButton, EventArgs.Empty);
        }
    }

    private void disableFallenDisc()
    {
        m_TimerFall.Enabled = false;
        m_TimerFall.Stop();
        m_PictureBoxFallenDisc.Visible = false;
        m_PictureBoxFallenDisc.Enabled = false;
        v_IsDiscFinishedFalling = true;
    }

    private void On_MouseMove(object sender, MouseEventArgs e)
    {
        m_PictureBoxCursorDisc.BringToFront();
        m_PictureBoxCursorDisc.Location = this.PointToClient(Cursor.Position);
    }

    private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
    {
        FormAbout About = new FormAbout();
        About.ShowDialog();
    }
}
